package com.huwei.data.impl;

import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.huwei.data.CacheDataSource;
import com.huwei.data.manager.DataSourceManagerFacotry;
import com.huwei.data.manager.DataSourceOperation;
import com.huwei.util.RedisUtil;
import com.huwei.vo.TargetCacheInfo;


@Order(6)
@Component
public class RedisSmsCodeDataSource  implements CacheDataSource{
	
	@Autowired
	private RedisUtil redisUtil;
	
	private Object invokeNextMethod() {
		return DataSourceManagerFacotry.getDataSourceUtil().invokeMethodByNextDataSource(CacheDataSource.class, this.getClass());
	}
	
	private DataSourceOperation next() {
		return  DataSourceManagerFacotry.getDataSourceUtil().next(CacheDataSource.class, this.getClass());
	}

	public Object save(TargetCacheInfo targetCacheInfo , Object value) {
		return save(targetCacheInfo, value, 0);
	}

	public Object save(TargetCacheInfo targetCacheInfo , Object value, long timeout) {
		return save(targetCacheInfo, value, timeout, TimeUnit.MILLISECONDS);
	}

	public Object save(TargetCacheInfo targetCacheInfo , Object value, long timeout, TimeUnit timeUnit) {
		Object old = redisUtil.opsForString().get(targetCacheInfo.getKey());
		if(Objects.nonNull(old)) {
			return old;
		}
		return update(targetCacheInfo, value, timeout, timeUnit);
	}

	public <V> V save(TargetCacheInfo targetCacheInfo , Callable<V> callable) {
		return save(targetCacheInfo, callable, 0);
	}

	public <V> V save(TargetCacheInfo targetCacheInfo , Callable<V> callable, long timeout) {
		return save(targetCacheInfo, callable, timeout ,TimeUnit.MILLISECONDS);
	}

	@SuppressWarnings("unchecked")
	public <V> V save(TargetCacheInfo targetCacheInfo , Callable<V> callable, long timeout, TimeUnit timeUnit) {
		Object old = redisUtil.opsForString().get(targetCacheInfo.getKey());
		if(Objects.nonNull(old)) {
			return (V) old;
		}
		return update(targetCacheInfo, callable, timeout, timeUnit);
	}

	public Object update(TargetCacheInfo targetCacheInfo , Object value) {
		return update(targetCacheInfo, value, 0);
	}

	public Object update(TargetCacheInfo targetCacheInfo , Object value, long timeout) {
		return update(targetCacheInfo, value, timeout, TimeUnit.MICROSECONDS);
	}

	public Object update(TargetCacheInfo targetCacheInfo , Object value, long timeout, TimeUnit timeUnit) {
		redisUtil.opsForString().set(targetCacheInfo.getKey(), value, timeout, timeUnit);
		invokeNextMethod();
		return value;
	}

	public <V> V update(TargetCacheInfo targetCacheInfo , Callable<V> callable) {
		return update(targetCacheInfo, callable, 0);
	}

	public <V> V update(TargetCacheInfo targetCacheInfo , Callable<V> callable, long timeout) {
		return update(targetCacheInfo, callable, timeout, TimeUnit.MILLISECONDS);
	}

	@SuppressWarnings("unchecked")
	public <V> V update(TargetCacheInfo targetCacheInfo , Callable<V> callable, long timeout, TimeUnit timeUnit) {
		Object value = null;
		DataSourceOperation dso = next();
		if(Objects.nonNull(dso)) {
			value = next().invokeCurrentMethod();
		}
		if(Objects.nonNull(value)) {
			redisUtil.opsForString().set(targetCacheInfo.getKey(), value, timeout, timeUnit);
		}
		return (V) value;
	}

	public Object find(TargetCacheInfo targetCacheInfo ) {
		Object value = redisUtil.opsForString().get(targetCacheInfo.getKey());
		if(Objects.nonNull(value)) {
			return value;
		}
		return invokeNextMethod();
	}

	public void delete(TargetCacheInfo targetCacheInfo ) {
		redisUtil.delKey(targetCacheInfo.getKey());
		invokeNextMethod();
	}
}
